<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="content-type" content="text/html" charset="utf-8"/>
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"/>
    <meta http-equiv="X-UA-Compatible" content="ie=edge"/>
    <title>Title</title>
    <link rel="stylesheet" href="../font-awesome/css/font-awesome.css">
    <link rel="stylesheet" href="../bootstrap/dist/css/bootstrap.css">
    <link rel="stylesheet" href="cropper.css">
    <style>
        img {
            max-width: 100%; /* This rule is very important, please do not ignore this! */
        }

        .image-editor__content__action{
        }

        .image-wrapper, .watermark-canvas{
            width: 500px;
            height: 500px;
            box-shadow: 0 0 4px 2px #f1f1f1;
        }
        .sidebar__item{
            padding: 20px;
            font-size: 36px;
            display: flex;
            flex-flow: column;
            align-items: center;
            color: #666;
            cursor: pointer;
        }
        .sidebar__item.active{
            color: #f40;
        }
        .sidebar__item:hover{
            color: #f88;
        }
        .sidebar__item__text{
            font-size: 24px;
        }
    </style>
</head>
<body>
<div>
    <div class="image-editor container">
        <div class="row">
            <div class="col-sm-3 image-editor__sidebar">
                <div class="sidebar__item btn-crop active">
                    <i class="fa fa-crop" aria-hidden="true" alt="裁剪"></i>
                    <span class="sidebar__item__text">裁剪</span>
                </div>
                <div class="sidebar__item btn-water-watermark">
                    <i class="fa fa-smile-o" aria-hidden="true" alt="水印"></i>
                    <span class="sidebar__item__text">水印</span>
                </div>
            </div>
            <div class="col-sm-9">
                <div class="image-editor__content image-editor__content--crop">
                    <div class="image-editor__content__action">
                        <button class="btn btn-change-image">更换图片</button>
                        <input class="file-input sr-only" type="file" accept="image/*">

                        <button class="btn btn-rotate"><i class="fa fa-undo" aria-hidden="true" alt="旋转"></i></button>
                    </div>
                    <div class="image-editor__main">
                        <div class="image-wrapper"><img class="image-editor__main__image" src="test.jpg"></div>
                        <button class="btn btn-crop-confirm">确定裁剪</button>
                    </div>
                </div>
                <div class="image-editor__content image-editor__content--watermark">
                    <div class="image-editor__content__action">
                        <button class="btn btn-change-image">更换图片</button>
                        <input class="file-input sr-only" type="file" accept="image/*">

                        <div class="form-check form-check-inline">
                            <input class="form-check-input" id="watermark_type_2" name="watermark_type" type="radio" value="2">
                            <label class="form-check-label" for="watermark_type_2">平铺水印</label>

                            <input class="form-check-input" id="watermark_type_1" name="watermark_type" type="radio" value="1">
                            <label class="form-check-label" for="watermark_type_1">单个水印</label>

                            <input class="form-check-input" id="watermark_type_0"  name="watermark_type" type="radio" value="0" checked>
                            <label class="form-check-label" for="watermark_type_0">无水印</label>
                        </div>

                        <button class="btn btn-rotate"><i class="fa fa-undo" aria-hidden="true" alt="旋转"></i></button>
                    </div>
                    <div>
                        <canvas id="watermark_canvas" height="500" width="500" class="watermark-canvas"></canvas>
                        <canvas id="watermark_canvas_temp" style="display: none"></canvas>
                    </div>
                    <div>
                        <button class="btn btn-watermark-confirm">保存水印</button>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <div>
        <img style="width: 80px;" class="result">
    </div>
</div>
<script>
//避免屏幕放大对fabric的影响
    window.devicePixelRatio = 1;
</script>
<script src="../jquery-3.5.1.js"></script>
<script src="../bootstrap/dist/js/bootstrap.bundle.js"></script>
<script src="cropper.js"></script>
<script src="jquery-cropper.js"></script>
<script src="../fabric.min.js"></script>
<script>
    var imageUrl = '';
    var $image = $('.image-editor__main__image');
    var canvas = __canvas = new fabric.Canvas('watermark_canvas', {
        //centeredRotation: true
    });
    //$image.cropper('destroy');
    // Get the Cropper.js instance after initialized
    //var cropper = $image.data('cropper');

    function preview(url) {
        $('.result').attr('src', url)
    }

    const watermark = {
        $el: $('.image-editor__content--watermark'),
        imageUrl: '',
        imageF: {},
        type: 0,
        watermarkIconOne:  './watermark-icon-1.png',
        watermarkIconFull: './watermark-icon-2.png',
        init(){
            this.bindEvent();
        },
        bindEvent(){
            let that = this;

            this.$el.on('click', 'input[type=radio][name=watermark_type]', function () {
                let value = $(this).val();
                console.log(value)
                that.type = value;
                that.setWatermark(value);
            })

            //逆时针旋转
            this.$el.on('click', '.btn-rotate', function () {
                let angle = that.imageF.angle + 90;
                that.rotate(angle);
            })

            //更换图片, 打开系统图片选择框
            this.$el.on('click','.btn-change-image', function () {
                that.$el.find('.file-input').trigger('click');
            })

            //确定选择图片, 更换至图层
            this.$el.on('change','.file-input', function () {
                read(this.files).then((data) => {
                    that.imageUrl = data.url;
                    that.setWatermark( that.type);
                }).catch((e) => {
                    alert('选择失败');
                });
            })
        },
        rotate(angle){
            this.imageF.set({
                angle : angle
            });
            canvas.renderAll();
        },
        toUrlCustom(x, y, width, height){
            let imageData = canvas.contextContainer.getImageData(x, y, width, height)

            let tempCanvas = $('#watermark_canvas_temp').get(0);// document.createElement('canvas');
            tempCanvas.width =  width;
            tempCanvas.height =  height;
            let tempCtx = tempCanvas.getContext('2d');

            tempCtx.clearRect(0, 0, tempCanvas.width ,tempCanvas.height)

            tempCtx.putImageData(imageData, 0, 0);
            let tempUrl = tempCanvas.toDataURL();

            //preview(tempUrl);
            return tempUrl;
        },
        toUrl(){
            let imageF = this.imageF;
            return this.toUrlCustom(imageF.realLeft, imageF.realTop, imageF.width * imageF.scaleX, imageF.height * imageF.scaleY);
        },
        async setWatermark(type){
            if (type === undefined){
                type = 0;
                $('#watermark_type_0').prop('checked', true);
            }
            type = parseInt(type);

            canvas.clear();
            this.imageF = await this.addFabricImage(this.imageUrl);
            switch (type) {
                case 1:
                    await this.setOneWatermark(); break;
                case 2:
                    await this.setFullWatermark(); break;
                default: // 0
                    break;
            }
            setTimeout(()=>{
                this.toUrl()
            }, 100)
        },
        async setOneWatermark(){
            let image = await this.loadImage(this.watermarkIconOne);
            //等比缩放高
            let imageF = new fabric.Image(image, {
                left: canvas.width / 2,
                top: canvas.height / 2
            });
            imageF.scale(0.1);
            canvas.add(imageF);
        },
        async setFullWatermark(){
            let image = await this.loadImage(this.watermarkIconFull);
            let imageF = new fabric.Image(image, {
                hasControls: false,
                selectable: false,
                left: 0,
                top: 0,
                scaleX:  canvas.width / image.naturalWidth,
                scaleY:  canvas.height / image.naturalHeight
            });
            canvas.add(imageF);
            return imageF;
        },
        async addFabricImage(base64) {
            if(!base64) return;

            let image = await this.loadImage(base64);

            const heightRatio = image.naturalHeight / canvas.height;
            const widthRatio = image.naturalWidth / canvas.width;

            const ratio = heightRatio > widthRatio ? widthRatio : heightRatio;

            let scale = canvas.width / image.naturalWidth;
            let imageWidth, imageHeight, x = 0 ,y = 0;
            if (heightRatio > widthRatio) {
                //定高
                imageHeight = canvas.height;
                imageWidth = imageHeight/ (image.naturalHeight / image.naturalWidth);
                //等比缩放高
                x= (canvas.width - imageWidth) / 2;
                scale = canvas.height / image.naturalHeight;
            }else{
                //定宽
                imageWidth =  canvas.width;
                //等比缩放高
                imageHeight = imageWidth / (image.naturalWidth / image.naturalHeight);
                y = (canvas.height - imageHeight) / 2;
            }

            let rotateLeft= x + imageWidth / 2, //旋转中心为center时, 旋转后, 会右上移动图片/2
                rotateTop= y + imageHeight / 2;
            let imageF = new fabric.Image(image, {
                hasControls: false,
                selectable: false,
                realLeft: x,
                realTop: y,
                left: rotateLeft,
                top: rotateTop,
                originX: 'center',
                originY: 'center',
            });
            imageF.scale(scale);//图片缩小
            canvas.add(imageF);
            return imageF;
        },
        loadImage(src) {
            return new Promise((resolve, reject) => {
                let image = new Image();
                if (src.indexOf('https://') === 0 || src.indexOf('http://') === 0)
                    image.crossOrigin = '*';//anonymous

                image.src = src;
                image.onload = function () {
                    resolve(image);
                }
                image.onerror = function () {
                    reject(new Error('图片加载失败'));
                }
            })
        }
    }

    init();
    function init(){
        $('.image-editor__sidebar').find('.sidebar__item.active').trigger('click');
        $('.image-editor__content--crop').show().siblings().hide();

        initCrop();
        watermark.init();
    }
    function initCrop(){
        //https://github.com/fengyuanchen/cropperjs/blob/master/README.md
        $image.cropper({
            autoCrop: false,
            dragMode: 'move', //crop move none
            //aspectRatio: 16 / 9, //默认裁剪[框]的比例
            cropend: function () {
                let url =  $image.data('cropper').getCroppedCanvas().toDataURL();
                preview(url);
            }
        });
        bindEvent();
    }

    function bindEvent(){
        //侧边栏选中样式
        $('.image-editor__sidebar').on('click', '.sidebar__item', function () {
            $(this).siblings().removeClass('active')
            $(this).addClass('active')
        })

        //开始裁剪
        $('.btn-crop').on('click', function () {
            $image.cropper('replace', imageUrl);
            setTimeout(()=>{
                $image.cropper('resize');
                $image.cropper('reset');
                $image.cropper('crop');
            }, 0)
            $('.image-editor__content--crop').show().siblings().hide();
        })

        //切换到水印
        $('.btn-water-watermark').on('click', function () {
            //var url = saveCrop();
            var url =  $image.data('cropper').url; //使用为裁剪前的url
            //清除裁剪框
            $image.cropper('clear');
            //重置视图, 避免 缩放,移动,旋转 影响
            $image.cropper('reset');

            $('.image-editor__content--watermark').show().siblings().hide()

            imageUrl = url;
            watermark.imageUrl = url;
            watermark.setWatermark();
        })

        //确定裁剪
        $('.image-editor__content--crop .btn-crop-confirm').on('click', function () {
            saveCrop();
        })

        //保存水印
        $('.image-editor__content--watermark .btn-watermark-confirm').on('click', function () {
            imageUrl = watermark.toUrl();
            watermark.imageUrl = imageUrl;
            watermark.setWatermark();
        })

        //逆时针旋转
        $('.image-editor__content--crop .btn-rotate').on('click', function () {
            $image.cropper('rotate', -90);
        })

        //更换图片, 打开系统图片选择框
        $('.image-editor__content--crop .btn-change-image').on('click', function () {
            $('.image-editor__content--crop .file-input').trigger('click');
        })

        //确定选择图片, 更换至图层
        $('.image-editor__content--crop .file-input').on('change', function () {
            read(this.files).then((data) => {
                $image.cropper('replace', data.url);
            }).catch((e) => {
                alert('选择失败');
            });
        })

    }

    function saveCrop(){
        let cropUrl = $image.cropper('getCroppedCanvas').toDataURL();
        $image.cropper('replace', cropUrl);
        return cropUrl;
    }
    function read(files) {
        return new Promise((resolve, reject) => {
            if (!files || files.length === 0) {
                resolve();
                return;
            }

            const file = files[0];

            if (/^image\/\w+$/.test(file.type)) {
                if (URL) {
                    resolve({
                        loaded: true,
                        name: file.name,
                        type: file.type,
                        url: URL.createObjectURL(file),
                    });
                } else {
                    reject(new Error('Your browser is not supported.'));
                }
            } else {
                reject(new Error('Please choose an image file.'));
            }
        });
    }


</script>
</body>
</html>